'use client';

import React, { createContext, useContext, useEffect, useState, useCallback, useRef } from 'react';
import io, { Socket } from 'socket.io-client';
import { useAuth } from '@/hooks/use-auth';
import { SocketContextType, BlockEditData, UserStatus, UserActivityData, TypingData, PermissionChangeData, CommentData } from '@/types/socket';

const SocketContext = createContext<SocketContextType | undefined>(undefined);

// 增强的Socket配置
const SOCKET_CONFIG = {
  reconnectionAttempts: 10, // 增加重连尝试次数
  reconnectionDelay: 1000, // 初始重连延迟
  reconnectionDelayMax: 10000, // 最大重连延迟
  timeout: 20000, // 增加超时时间
  transports: ['polling', 'websocket'], // 确保使用正确的传输方式
  forceNew: true, // 强制创建新连接
  autoConnect: false, // 初始化时不自动连接，手动控制连接
};

// 最大重连尝试次数
const MAX_RECONNECT_ATTEMPTS = 10;

export const SocketProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const { user } = useAuth();
  const [socket, setSocket] = useState<Socket | null>(null);
  const [isConnected, setIsConnected] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [connectionState, setConnectionState] = useState<{
    status: 'connected' | 'disconnected' | 'connecting' | 'reconnecting';
    lastConnected?: number;
    reconnectAttempt?: number;
    error?: string;
  }>({
    status: 'disconnected'
  });
  const [latency, setLatency] = useState<number>(0);
  const [offlineMode, setOfflineMode] = useState(false); // 新增离线模式状态
  
  // 使用ref跟踪重连尝试次数
  const reconnectAttempts = useRef<number>(0);
  
  // 使用ref跟踪自动重连计时器
  const reconnectTimer = useRef<NodeJS.Timeout | null>(null);
  
  // 使用ref跟踪ping间隔
  const pingIntervalRef = useRef<NodeJS.Timeout | null>(null);

  // 清除所有计时器的函数
  const clearAllTimers = () => {
    if (pingIntervalRef.current) {
      clearInterval(pingIntervalRef.current);
      pingIntervalRef.current = null;
    }
    
    if (reconnectTimer.current) {
      clearTimeout(reconnectTimer.current);
      reconnectTimer.current = null;
    }
  };

  // 初始化Socket连接
  useEffect(() => {
    if (!user) return;

    // 清除之前的计时器
    clearAllTimers();
    
    // 重置重连尝试次数
    reconnectAttempts.current = 0;

    // 修复Socket.io URL问题，确保正确的URL格式
    const socketUrl = process.env.NEXT_PUBLIC_SOCKET_URL || window.location.origin;
    console.log('尝试连接Socket.io:', socketUrl);
    
    const socketInstance = io(socketUrl, {
      withCredentials: true,
      path: '/api/socket',
      auth: {
        userId: user.id,
        userName: user.name,
        userImage: user.image
      },
      ...SOCKET_CONFIG
    });

    socketInstance.on('connect', () => {
      console.log('Socket连接成功');
      setIsConnected(true);
      setConnectionState({
        status: 'connected',
        lastConnected: Date.now()
      });
      setError(null);
      setOfflineMode(false); // 断开连接时禁用离线模式
      
      // 重置重连尝试次数
      reconnectAttempts.current = 0;
    });

    socketInstance.on('disconnect', (reason) => {
      console.log('Socket断开连接:', reason);
      setIsConnected(false);
      setConnectionState({
        ...connectionState,
        status: 'disconnected'
      });
      
      // 如果是服务器主动断开或传输关闭，尝试自动重连
      if (reason === 'io server disconnect' || reason === 'transport close') {
        // 使用指数退避算法计算重连延迟
        const delay = Math.min(
          SOCKET_CONFIG.reconnectionDelay * Math.pow(1.5, reconnectAttempts.current),
          SOCKET_CONFIG.reconnectionDelayMax
        );
        
        console.log(`将在 ${delay}ms 后尝试重连...`);
        
        // 设置自动重连计时器
        reconnectTimer.current = setTimeout(() => {
          if (reconnectAttempts.current < MAX_RECONNECT_ATTEMPTS) {
            console.log(`错误后重连尝试 #${reconnectAttempts.current + 1}`);
            socketInstance.connect();
            reconnectAttempts.current++;
          } else {
            console.error('达到最大重连尝试次数，停止重连');
            setError('无法连接到服务器，应用将在离线模式下运行');
            setOfflineMode(true); // 启用离线模式
          }
        }, delay);
      }
    });

    socketInstance.on('connect_error', (err) => {
      console.error('Socket连接错误:', err);
      setIsConnected(false);
      setError(err.message);
      setConnectionState({
        status: 'disconnected',
        error: err.message
      });
      
      // 记录详细错误信息以便调试
      try {
        console.error('连接错误详情:', err.message || '未知错误');
        if (err) {
          // 安全地提取错误属性
          const errorInfo = {
            message: err.message || '未知错误',
            name: err.name,
            stack: err.stack
          };
          console.error('错误信息:', errorInfo);
        }
      } catch (logError) {
        console.error('记录错误详情时出错:', logError);
      }
    });

    socketInstance.on('reconnect_attempt', (attemptNumber) => {
      console.log(`Socket重连尝试 #${attemptNumber}`);
      setConnectionState({
        status: 'reconnecting',
        reconnectAttempt: attemptNumber
      });
    });

    socketInstance.on('reconnect', () => {
      console.log('Socket重连成功');
      setIsConnected(true);
      setConnectionState({
        status: 'connected',
        lastConnected: Date.now()
      });
      setError(null);
      
      // 重置重连尝试次数
      reconnectAttempts.current = 0;
    });

    socketInstance.on('reconnect_error', (err) => {
      console.error('Socket重连错误:', err);
      setError(err.message);
      setConnectionState({
        ...connectionState,
        error: err.message
      });
    });

    socketInstance.on('reconnect_failed', () => {
      console.error('Socket重连失败');
      setConnectionState({
        status: 'disconnected',
        error: '重连失败，已达到最大尝试次数'
      });
    });

    socketInstance.on('pong', (serverTime: number, pingLatency: number) => {
      setLatency(pingLatency);
    });

    setSocket(socketInstance);

    // 定期发送ping维持连接
    pingIntervalRef.current = setInterval(() => {
      if (socketInstance.connected) {
        const start = Date.now();
        socketInstance.emit('ping', (serverTime: number) => {
          const latency = Date.now() - start;
          setLatency(latency);
        });
      }
    }, 30000);

    return () => {
      clearAllTimers();
      socketInstance.disconnect();
      setSocket(null);
    };
  }, [user]);

  // 重新连接
  const reconnect = useCallback(() => {
    if (socket) {
      // 清除之前的重连计时器
      if (reconnectTimer.current) {
        clearTimeout(reconnectTimer.current);
        reconnectTimer.current = null;
      }
      
      // 重置重连尝试次数
      reconnectAttempts.current = 0;
      
      // 重置错误和离线模式
      setError(null);
      setOfflineMode(false);
      
      console.log('手动重新连接...');
      socket.connect();
      setConnectionState({
        status: 'connecting'
      });
    } else {
      console.error('无法重连: Socket实例不存在');
    }
  }, [socket]);

  // 断开连接
  const disconnect = useCallback(() => {
    if (socket) {
      socket.disconnect();
      setConnectionState({
        status: 'disconnected'
      });
    }
  }, [socket]);

  // 检查连接状态并尝试恢复
  useEffect(() => {
    // 如果连接状态为断开且有错误，但用户存在，尝试自动重连
    if (connectionState.status === 'disconnected' && connectionState.error && user) {
      const delay = 5000 + Math.random() * 5000; // 添加随机延迟，防止同时重连
      console.log(`检测到连接断开，将在 ${Math.round(delay/1000)} 秒后尝试自动恢复连接...`);
      
      const timer = setTimeout(() => {
        // 仅当状态仍为断开时重连
        if (connectionState.status === 'disconnected') {
          console.log('自动恢复连接...');
          reconnect();
        }
      }, delay);
      
      return () => clearTimeout(timer);
    }
  }, [connectionState.status, connectionState.error, user, reconnect]);

  // 加入项目
  const joinProject = useCallback((projectId: string) => {
    if (!socket || !isConnected || !user) return;
    
    console.log('加入项目:', projectId);
    socket.emit('join-project', {
      projectId,
      user: {
        id: user.id,
        name: user.name || '未知用户',
        image: user.image
      },
      timestamp: Date.now()
    });
    
    // 记录协作会话
    try {
      // 为每个项目创建或更新协作会话记录
      fetch(`/api/projects/${projectId}/collaboration-session`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          userId: user.id,
          status: 'active',
          lastActive: new Date()
        })
      }).catch(err => console.error('记录协作会话失败:', err));
    } catch (error) {
      console.error('记录协作会话失败:', error);
    }
  }, [socket, isConnected, user]);
  
  // 离开项目
  const leaveProject = useCallback((projectId: string) => {
    if (!socket || !isConnected || !user) return;
    
    console.log('离开项目:', projectId);
    socket.emit('leave-project', {
      projectId,
      user: {
        id: user.id,
        name: user.name || '未知用户',
        image: user.image
      },
      timestamp: Date.now()
    });
    
    // 更新协作会话状态为离线
    try {
      fetch(`/api/projects/${projectId}/collaboration-session`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          userId: user.id,
          status: 'offline',
          lastActive: new Date()
        })
      }).catch(err => console.error('更新协作会话状态失败:', err));
    } catch (error) {
      console.error('更新协作会话状态失败:', error);
    }
  }, [socket, isConnected, user]);

  // 加入任务
  const joinTask = useCallback((taskId: string) => {
    if (socket && isConnected) {
      socket.emit('join-task', taskId);
    }
  }, [socket, isConnected]);

  // 离开任务
  const leaveTask = useCallback((taskId: string) => {
    if (socket && isConnected) {
      socket.emit('leave-task', taskId);
    }
  }, [socket, isConnected]);

  // 发送任务更新
  const sendTaskUpdate = useCallback((data: any) => {
    if (socket && isConnected) {
      socket.emit('task-update', data);
    }
  }, [socket, isConnected]);

  // 发送评论
  const sendComment = useCallback((data: CommentData) => {
    if (!socket || !isConnected) return;
    socket.emit('new-comment', data);
  }, [socket, isConnected]);

  // 发送文档更新
  const sendDocUpdate = useCallback((data: any) => {
    if (socket && isConnected) {
      socket.emit('doc-update', data);
    }
  }, [socket, isConnected]);

  // 发送光标位置
  const sendCursorPosition = useCallback((data: any) => {
    if (socket && isConnected) {
      socket.emit('cursor-move', data);
    }
  }, [socket, isConnected]);

  // 发送块编辑状态
  const sendBlockEdit = useCallback((data: BlockEditData) => {
    if (socket && isConnected) {
      socket.emit('block-edit', data);
    }
  }, [socket, isConnected]);

  // 发送建议
  const sendSuggestion = useCallback((data: any) => {
    if (socket && isConnected) {
      socket.emit('new-suggestion', data);
    }
  }, [socket, isConnected]);

  // 锁定文档
  const lockDocument = useCallback((data: any) => {
    if (socket && isConnected) {
      socket.emit('doc-lock', data);
    }
  }, [socket, isConnected]);

  // 解锁文档
  const unlockDocument = useCallback((data: any) => {
    if (socket && isConnected) {
      socket.emit('doc-unlock', data);
    }
  }, [socket, isConnected]);

  // 设置用户状态
  const setUserStatus = useCallback((status: UserStatus) => {
    if (socket && isConnected) {
      socket.emit('user-status', status);
    }
  }, [socket, isConnected]);

  // 设置用户活动
  const setUserActivity = useCallback((data: UserActivityData) => {
    if (socket && isConnected) {
      socket.emit('user-activity', data);
    }
  }, [socket, isConnected]);

  // 开始打字
  const startTyping = useCallback((data: TypingData) => {
    if (socket && isConnected) {
      socket.emit('typing-start', data);
    }
  }, [socket, isConnected]);

  // 停止打字
  const stopTyping = useCallback((data: TypingData) => {
    if (socket && isConnected) {
      socket.emit('typing-end', data);
    }
  }, [socket, isConnected]);

  // 更改权限
  const changePermission = useCallback((data: PermissionChangeData) => {
    if (socket && isConnected) {
      socket.emit('permission-change', data);
    }
  }, [socket, isConnected]);

  // 通用的事件监听器创建函数
  const createEventListener = useCallback((eventName: string) => {
    return (handler: (data: any) => void) => {
      if (!socket) return () => {};

      socket.on(eventName, handler);
      return () => {
        socket.off(eventName, handler);
      };
    };
  }, [socket]);

  // 监听任务更新
  const onTaskUpdated = useCallback(
    createEventListener('task-updated'),
    [createEventListener]
  );

  // 监听评论添加
  const onCommentAdded = useCallback(
    createEventListener('new-comment-added'),
    [createEventListener]
  );

  // 监听文档更新
  const onDocUpdated = useCallback(
    createEventListener('doc-updated'),
    [createEventListener]
  );

  // 监听光标移动
  const onCursorMoved = useCallback(
    createEventListener('cursor-moved'),
    [createEventListener]
  );

  // 监听块编辑
  const onBlockEditing = useCallback(
    createEventListener('block-editing'),
    [createEventListener]
  );

  // 监听建议添加
  const onSuggestionAdded = useCallback(
    createEventListener('new-suggestion-added'),
    [createEventListener]
  );

  // 监听用户状态变化
  const onUserStatusChanged = useCallback(
    createEventListener('user-status-changed'),
    [createEventListener]
  );

  // 监听用户活动
  const onUserActivity = useCallback(
    createEventListener('user-activity-update'),
    [createEventListener]
  );

  // 监听用户开始打字
  const onUserTyping = useCallback(
    createEventListener('user-typing'),
    [createEventListener]
  );

  // 监听用户停止打字
  const onUserStoppedTyping = useCallback(
    createEventListener('user-stopped-typing'),
    [createEventListener]
  );

  // 监听通知
  const onNotification = useCallback(
    createEventListener('notification'),
    [createEventListener]
  );

  // 监听项目更新
  const onProjectUpdated = useCallback(
    createEventListener('project-updated'),
    [createEventListener]
  );

  // 监听成员加入
  const onMemberJoined = useCallback(
    createEventListener('member-joined'),
    [createEventListener]
  );

  // 监听成员离开
  const onMemberLeft = useCallback(
    createEventListener('member-left'),
    [createEventListener]
  );

  // 监听文档锁定
  const onDocumentLocked = useCallback(
    createEventListener('doc-lock'),
    [createEventListener]
  );

  // 监听文档解锁
  const onDocumentUnlocked = useCallback(
    createEventListener('doc-unlock'),
    [createEventListener]
  );

  // 监听权限变更
  const onPermissionChanged = useCallback(
    createEventListener('permission-changed'),
    [createEventListener]
  );

  // Socket上下文实现
  const socketValue: SocketContextType = {
    socket,
    isConnected,
    connectionState,
    error,
    latency,
    offlineMode,
    
    // 房间管理
    joinProject: useCallback((projectId: string) => {
      if (socket && isConnected) {
        socket.emit('join-project', projectId);
      } else if (offlineMode) {
        console.log('[离线模式] 加入项目:', projectId);
      }
    }, [socket, isConnected, offlineMode]),
    
    leaveProject: useCallback((projectId: string) => {
      if (socket && isConnected) {
        socket.emit('leave-project', projectId);
      } else if (offlineMode) {
        console.log('[离线模式] 离开项目:', projectId);
      }
    }, [socket, isConnected, offlineMode]),
    
    joinTask: useCallback((taskId: string) => {
      if (socket && isConnected) {
        socket.emit('join-task', taskId);
      } else if (offlineMode) {
        console.log('[离线模式] 加入任务:', taskId);
      }
    }, [socket, isConnected, offlineMode]),
    
    leaveTask: useCallback((taskId: string) => {
      if (socket && isConnected) {
        socket.emit('leave-task', taskId);
      } else if (offlineMode) {
        console.log('[离线模式] 离开任务:', taskId);
      }
    }, [socket, isConnected, offlineMode]),
    
    // 任务相关
    sendTaskUpdate,
    sendComment,
    
    // 文档相关
    sendDocUpdate,
    sendCursorPosition,
    sendBlockEdit,
    sendSuggestion,
    lockDocument,
    unlockDocument,
    
    // 用户状态
    setUserStatus,
    setUserActivity,
    startTyping,
    stopTyping,
    
    // 权限相关
    changePermission,
    
    // 事件监听
    onTaskUpdated,
    onCommentAdded,
    onDocUpdated,
    onCursorMoved,
    onBlockEditing,
    onSuggestionAdded,
    onUserStatusChanged,
    onUserActivity,
    onUserTyping,
    onUserStoppedTyping,
    onNotification,
    onProjectUpdated,
    onMemberJoined,
    onMemberLeft,
    onDocumentLocked,
    onDocumentUnlocked,
    onPermissionChanged,
    
    // 连接管理
    reconnect,
    disconnect
  };

  return (
    <SocketContext.Provider value={socketValue}>
      {children}
    </SocketContext.Provider>
  );
};

export const useSocket = (): SocketContextType => {
  const context = useContext(SocketContext);
  if (context === undefined) {
    throw new Error('useSocket必须在SocketProvider内部使用');
  }
  return context;
}; 